#include <string.h>
#include "els_vm.h"
#include "els.h"
#include "els_vm_tree.h"
#include "unit.h"
#define els_strcmp(a,b)	(a[0]<b[0]?(-1):(a[0]>b[0]?(1):strcmp(a,b))) 
typedef struct StringNode {
    struct StringNode *next;
    Type_Tagged_String ts;
}StringNode;

static StringNode *string_root = NULL;

static Els_Type_Tree *constant_root = NULL;

static Els_Type_Tree *tree_create (Els_Type_Tree **node, char *str){
    if (*node == NULL){
        *node = (Els_Type_Tree *) els_vm_malloc(sizeof(Els_Type_Tree)+strlen(str));
        (*node)->left = (*node)->right = NULL;
        strcpy((*node)->ts.str, str);
        (*node)->ts.marked = 0;
        (*node)->ts.hash = 0;
        (*node)->varindex = (*node)->constindex = NOT_USED;
        return *node;
    }else{
        int c = els_strcmp(str, (*node)->ts.str);
        if (c < 0) return tree_create(&(*node)->left, str);
        else if (c > 0) return tree_create(&(*node)->right, str);
        else return *node;
    }
}

Type_Tagged_String *els_createstring (char *str) {
    StringNode *newString;
    if (str == NULL) return NULL;
    els_pack();
    newString = (StringNode *)els_vm_malloc(sizeof(StringNode)+strlen(str));
    newString->ts.marked = 0;
    newString->ts.hash = 0;
    strcpy(newString->ts.str, str);
    newString->next = string_root;
    string_root = newString;
    return &(newString->ts);
}


Els_Type_Tree *els_lexgetstring (char *str) {
    return tree_create(&constant_root, str);
}

Long els_strcollector (void){
    StringNode *curr = string_root, *prev = NULL;
    Long counter = 0;
    while (curr){
        StringNode *next = curr->next;
        if (!curr->ts.marked){
            if (prev == NULL) string_root = next;
            else prev->next = next;
            els_vm_free(curr);
            ++counter;
        }else{
            curr->ts.marked = 0;
            prev = curr;
        }
        curr = next;
    }
    return counter;
}


static Els_Type_Tree *nodebysymbol (Els_Type_Tree *root, Word symbol){
    Els_Type_Tree *t;
    if (root == NULL) return NULL;
    if (root->varindex == symbol) return root;
    t = nodebysymbol(root->left, symbol);
    if (t) return t;
    return nodebysymbol(root->right, symbol);
}

Els_Type_Tree *els_vm_nodebysymbol (Word symbol){
    return nodebysymbol(constant_root, symbol); 
}

